/*
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program. If not, see <http://www.gnu.org/licenses/>.
 */
package org.merak.core.text.template;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;

import org.merak.core.annotation.Style;

public class TemplateFactory {

    //~ Methods ////////////////////////////////////////////////////////////////////////////////////
	//**********************************************************************************************
	public TemplateObject createTemplate(Class<?> clazz) {

		// Auxiliary
		List<TemplateProperty> list     = new ArrayList<TemplateProperty>();
		TemplateObject         object   = new TemplateObject();
		TemplateProperty       property = null;
		String                 name     = null;
		String                 prefix   = null;

		// Look for properties based on declared getters
		for (Method m : Reflect.listDistinctLineageMethods(clazz)) {
			// Try match a getter method
			Matcher matcher = Reflect.matchGetter(m);
			if (matcher==null) continue;
			prefix = matcher.group(1);
			name   = matcher.group(2);
			// Create a property based on getter
			property = new TemplateProperty();
			property.setName(this.toNonCapitalCase(name));
			property.setType(m.getReturnType());
			property.setPrefix(prefix);
			property.setGetter(m);
			property.setStyle(m.getAnnotation(Style.class));
			// Look for a setter
			this.findSetter(clazz,property);
			// Register the property
			list.add(property);
		}

		// Sort the list of properties based on z-index
		TemplateProperty[] array = list.toArray(new TemplateProperty[list.size()]);
		Arrays.sort(array,new ZIndexComparator());

		// Convert the property list into an array and add it to template
		object.setName      ( clazz.getSimpleName() );
		object.setClazz     ( clazz );
		object.setProperties( array );
		return object;

	}
	//**********************************************************************************************
	private void findSetter(Class<?> clazz,TemplateProperty p) {

		try {
			String setterName   = null;
			String propertyName = p.getCapitalName();
			if (p.hasPrefix("get")) setterName = "set"+propertyName   ; else
			if (p.hasPrefix("has")) setterName = "setHas"+propertyName; else
			if (p.hasPrefix("is" )) setterName = "set"+propertyName   ;
			p.setSetter( clazz.getMethod(setterName,p.getType()) );
		}
		catch (SecurityException e) {
			// TODO User log4j here
			e.printStackTrace();
		}
		catch (NoSuchMethodException e) {
			/* Do nothing, it only means the setter does not exist,
			 * what is perfectly normal */
		}

	}
	//**********************************************************************************************
	private String toNonCapitalCase(String s) {

		return Character.toLowerCase(s.charAt(0)) + s.substring(1);

	}
	//**********************************************************************************************

}
